#include "bureaucrat.h"
#include <fstream>
#include <utility>
#include <algorithm>
#include <string>
#include <sstream>
#include <vector>
#include <boost/graph/topological_sort.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include "logger.h"

/// pimpl implementation
struct BureaucratImpl {
	// convenience typedefs
	typedef boost::property<boost::vertex_name_t, std::string> VertexData;
	typedef boost::property<boost::edge_weight_t, double> EdgeData;
	typedef boost::adjacency_list<boost::vecS,
								  boost::vecS,
								  boost::directedS,
								  VertexData,
								  EdgeData> DependencyGraph;

	// implementation details
	DependencyGraph dependency_graph_;
};

Bureaucrat::Bureaucrat()
	: pimpl_(new BureaucratImpl())
{
	std::ifstream dot_file("courses.dot");
	course_dependencies(dot_file);
}

Bureaucrat::~Bureaucrat()
{
}

/// load streamed dot file
void Bureaucrat::course_dependencies(std::istream& dot_file)
{
	using namespace boost;
	typedef BureaucratImpl::DependencyGraph Graph;
	typedef graph_traits<Graph>::vertex_descriptor Vertex;
	typedef graph_traits<Graph>::vertex_iterator VertexIterator;
	typedef graph_traits<Graph>::edge_iterator EdgeIterator;
	typedef graph_traits<Graph>::edge_descriptor Edge;
	
	dynamic_properties dp;
	dp.property("node_id", get(vertex_name, pimpl_->dependency_graph_));

	if( read_graphviz(dot_file, pimpl_->dependency_graph_, dp) ) {
		std::stringstream ss;
		ss << num_vertices(pimpl_->dependency_graph_);
		std::string message;
		ss >> message;
		message += " courses loaded from streamed course dependencies.";
		Logger::instance()->message(message, 1);

		std::vector<Vertex> schedule;
		topological_sort(pimpl_->dependency_graph_,
						 std::back_inserter(schedule));
		std::vector<Vertex>::reverse_iterator vertices_start = schedule.rbegin();
		std::vector<Vertex>::reverse_iterator vertices_end = schedule.rend(); 
	}
	else {
		Logger::instance()->error("Courses failed to load.", 1);
	}
}

/// load streamed student profile
void Bureaucrat::student_profile(std::istream&)
{
}

/// generate the next schedule
void Bureaucrat::next_schedule()
{
}
